get_reg_by_offset函数如下:
在建立了寄存器模型后,可以直接通过层次引用的方式访问寄存器:
rm.invert.read(...);
但是出于某些原因,如果依然要使用地址来访问寄存器模型,那么此时可以使用get_reg_by_offset函数通过寄存器的地址得到 一个uvm_reg的指针,再调用此uvm_reg的read或者write就可以进行读写操作:
virtual task read_reg(input bit[15:0] addr, output bit[15:0] value);
uvm_status_e status;
uvm_reg target;
uvm_reg_data_t data;
uvm_reg_addr_t addrs[];
target = p_sequencer.p_rm.default_map.get_reg_by_offset(addr);
if(target == null)
`uvm_error("case0_cfg_vseq", $sformatf("can't find reg in register model with address: 'h%0h", addr))
target.read(status, data, UVM_FRONTDOOR);
void'(target.get_addresses(null,addrs));
if(addrs.size() == 1)
value = data[15:0];
else begin
int index;
for(int i = 0; i < addrs.size(); i++) begin
if(addrs[i] == addr) begin
data = data >> (16*(addrs.size() - i));
value = data[15:0];
break;
end
end
end
endtask
通过调用最顶层的reg_block的get_reg_by_offset,即可以得到任一寄存器的指针。
如果如7.4.1节(白皮书)那样使用了层次的寄存器模型,从最顶层的reg_block的get_reg_by_offset也可以得到子reg_block中的寄存器。即假如buf_blk的地址偏移是'h1000,其中有偏移为'h3的寄存器(即此寄存器的实际物理地址是'h1003),那么可以直接由p_rm.get_reg_by_offset('h1003)得到此寄存器,而不必使用p_rm.buf_blk.get_reg_by_offset('h3)。
如果没有使用7.4.4节所示的多地址寄存器,那么情况比较简单,上述代码会运行第39行的分支。当存在多个地址的情况下, 通过get_addresses函数可以得到这个函数的所有地址,其返回值是一个动态数组addrs。其中无论是大端还是小端,addrs[0]是LSB 对应的地址。即对于7.3.2节DUT中的counter(此DUT是大端),那么addrs[0]中存放的是‘h6。而假如是小端,两个地址分别 是'h1005和'h1006,那么addrs[0]中存放的是'h1005。第41到48行通过比较addrs中的地址与目标地址,最终得到要访问的数据。