UVM实战卷I学习笔记10——UVM中的寄存器模型(6)

UVM实战卷I学习笔记10——UVM中的寄存器模型(6)
⽬录
寄存器模型的⾼级⽤法
*使⽤reg_predictor
前⾯读操作的返回值介绍了左图的⽅式,这种⽅式要依赖于driver。当driver将读取值返回后,寄存器模型会更新寄存器的镜像值和期望值,这是寄存器模型的auto predict功能。在建⽴寄存器模型时使⽤如下语句打开此功能:rm.default_map.set_auto_predict(1);
除了左图使⽤driver的返回值更新寄存器模型外,还存在另⼀种形式如右图所⽰。这种形式是由monitor将从总线上收集到的transaction 交给寄存器模型,后者更新相应寄存器的值。
要使⽤这种⽅式更新数据,需要实例化⼀个reg_predictor,并为这个reg_predictor实例化⼀个adapter:
class base_test extends uvm_test;
reg_model rm;
my_adapter reg_sqr_adapter;
my_adapter mon_reg_adapter;
uvm_reg_predictor#(bus_transaction) reg_predictor;
endclass
function void base_test::build_phase(uvm_phase phase);
rm = reg_model::type_id::create("rm", this);
rm.build();
rm.lock_model();
reg_sqr_adapter =new("reg_sqr_adapter");
mon_reg_adapter =new("mon_reg_adapter");
reg_predictor =new("reg_predictor", this);//notice
env.p_rm = ;
endfunction
function void base_test::connect_phase(uvm_phase phase);
rm.default_map.set_sequencer(env.bus_agt.sqr, reg_sqr_adapter);
rm.default_map.set_auto_predict(1);//notice
reg_predictor.map = rm.default_map;
reg_predictor.adapter = mon_reg_adapter;
env.bus_t(reg_predictor.bus_in);
endfunction
在connect_phase中需要将reg_predictor和bus_agt的ap⼝连接在⼀起,并设置reg_predictor的adapter和map。只有设置了map后,才能将predictor和寄存器模型关联在⼀起。
当总线上**只有⼀个主设备(master)**时,左图和右图完全等价。有多个主设备时左图会漏掉某些trasaction。
经过上⾯代码的设置,事实上存在两条更新寄存器模型的路径:⼀是上⾯右图虚线所⽰的⾃动预测途径,⼆是经由predictor的途径。如果要彻底关掉虚线的更新路径:rm.default_map.set_auto_predict(0);
*使⽤UVM_PREDICT_DIRECT功能与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。
前⽂说过在通信系统中存在⼤量的计数器。当⽹络出现异常时借助这些计数器能够快速出问题所在,所以必须要保证这些计数器的正确性。⼀般会在仿真即将结束时使⽤mirror操作检查这些计数器的值是否与预期值⼀致。
在DUT中的计数器是不断累加的,但寄存器模型中的计数器则保持静⽌。参考模型会不断统计收到了多少包,那么怎么将这些统计数据传递给寄存器模型呢?
前⽂中介绍的所有操作都⽆法完成这个事情,⽆论是set还是write,或是poke;⽆论是后门访问还是前门访问。这个问题的实质是想⼈为地更新镜像值,但同时⼜不要对DUT进⾏任何操作。
UVM提供predict操作来实现这样的功能:
function bit uvm_reg::predict(uvm_reg_data_t value,
uvm_reg_byte_en_t be =-1,
uvm_predict_e kind = UVM_PREDICT_DIRECT,
uvm_path_e path = UVM_FRONTDOOR,
…);
其中第⼀个参数表⽰要预测的值,第⼆个参数是byte_en,默认-1的意思是全部有效,第三个参数是预测的类型,第四个参数是后门访问或者是前门访问。第三个参数预测类型有如下⼏种可以选择:
typedef enum{
UVM_PREDICT_DIRECT,
UVM_PREDICT_READ,
UVM_PREDICT_WRITE
} uvm_predict_e;
read/peek和write/poke操作在对DUT完成读写后也会调⽤此函数,只是给出的参数是UVM_PREDICT_READ和
UVM_PREDICT_WRITE。
要实现在参考模型中更新寄存器模型⽽⼜不影响DUT的值,需要使⽤UVM_PREDICT_DIRECT,即默认值:
task my_model::main_phase(uvm_phase phase);
p_ad(status, value, UVM_FRONTDOOR);
while(1) begin
<(tr);
if(value)
结晶紫invert_tr(new_tr);
counter = ();
length = new_tr.pload.size()+18;
counter = counter + length;
unter.predict(counter);//notice
ap.write(new_tr);
end
endtask
在my_model中每得到⼀个新的transaction,就先从寄存器模型中得到counter的期望值(此时与镜像值⼀致),之后将新的transaction 的长度加到counter中,最后使⽤predict函数将新的counter值更新到寄存器模型中。predict操作会更新镜像值和期望值。
在测试⽤例中,仿真完成后可以检查DUT中counter的值是否与寄存器模型中的counter值⼀致:
class case0_vseq extends uvm_sequence;
virtual task body();
dseq = case0_sequence::type_id::create("dseq");
dseq.start(p_sequencer.p_my_sqr);
#100000;
p_sequencer.unter.mirror(status, UVM_CHECK, UVM_FRONTDOOR);//注意是check模式
endtask
endclass
*寄存器模型的随机化与update
前⽂在向uvm_reg中加⼊uvm_reg_field时,是将加⼊的uvm_reg_field定义为rand类型:
class reg_invert extends uvm_reg;
轻芳烃rand uvm_reg_field reg_data;
endclass
无铬在将uvm_reg加⼊uvm_reg_block中时,同样定义为rand类型:
class reg_model extends uvm_reg_block;
rand reg_invert invert;
endclass
由此可以判断register_model⽀持randomize操作。可以在uvm_reg_block级别调⽤randomize函数,也可以在uvm_reg级别,甚⾄可以在uvm_reg_field级别调⽤:
assert(rm.randomize());
assert(rm.invert.randomize());
assert(_data.randomize());
但要使某个field能够随机化,只是将其定义为rand类型是不够的。在每个reg_field加⼊uvm_reg时,要调⽤其configure函数:
// parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset,
// is_rand, individually accessible
figure(this,1,0,"RW",1,0,1,1,0);
这个函数的第⼋个参数决定此field是否会在randomize时被随机化。但即使此参数为1,也不⼀定能够保证此field被随机化。当⼀个field的类型中没有写操作时,此参数设置是⽆效的。即此参数只在此field类型为RW、WRC、WRS、WO、W1、WO1时才有效。
因此要避免⼀个field被随机化,可以在以下三种⽅式中任选其⼀:
1. 当在uvm_reg中定义此field时,不要设置为rand类型。
2. 在调⽤此field的configure函数时,第⼋个参数设置为0。
3. 设置此field的类型为RO、RC、RS、WC、WS、W1C、W1S、W1T、W0C、W0S、W0T、W1SRC、W1CRS、W0SRC、
W0CRS、WSRC、WCRS、WOC、WOS中的⼀种(没有写操作)。
其中第⼀种⽅式也适⽤于关闭某个uvm_reg或者某个uvm_reg_block的randomize功能。
既然存在randomize,那么也可以为它们定义constraint:
佟星
class reg_invert extends uvm_reg;
rand uvm_reg_field reg_data;
constraint cons{
效益最大化reg_data.value ==0;
}
endclass
在施加约束时,要深⼊reg_field的value变量。
randomize会更新寄存器模型中的预期值:
function void uvm_reg_field::post_randomize();
m_desired = value;
endfunction: post_randomize
这与set函数类似。因此,可以在randomize完成后调⽤update任务,将随机化后的参数更新到DUT中。这特别适⽤于在仿真开始时随机化并配置参数。
扩展位宽
在reg_invert的new函数中,调⽤w时的第⼆个参数是16,这个数字⼀般表⽰系统总线的宽度,它可以是32、64、128等。
class reg_invert extends uvm_reg;
rand uvm_reg_field reg_data;
virtual function void build();
reg_data = uvm_reg_field::type_id::create("reg_data");
// parameter: parent, size, lsb_pos, access, volatile, reset value, has_reset, is_rand, indi
figure(this,1,0,"RW",1,0,1,1,0);
endfunction
`uvm_object_utils(reg_invert)
function new(input string name="reg_invert");
//parameter: name, size, has_coverage
endfunction
endclass
但在寄存器模型中,这个数字的默认最⼤值是64,它是通过⼀个宏来控制的:
`ifndef UVM_REG_DATA_WIDTH
`define UVM_REG_DATA_WIDTH 64
`endif
如果想要扩展系统总线的位宽,可通过重新定义这个宏来扩展。
与数据位宽相似的是地址位宽也有默认最⼤值限制,其默认值也是64:
`ifndef UVM_REG_ADDR_WIDTH
`define UVM_REG_ADDR_WIDTH 64
`endif
在默认情况下,字选择信号的位宽等于数据位宽除以8,它通过如下的宏来控制:
ifndef UVM_REG_BYTENABLE_WIDTH
`define UVM_REG_BYTENABLE_WIDTH((`UVM_REG_DATA_WIDTH-1)/8+1)//notice
`endif
如果想要使⽤其他值,也可以重新定义这个宏。
寄存器模型的其他常⽤函数
get_root_blocks
在以前例⼦中,若某处要使⽤寄存器模型,则必须将寄存器模型的指针传递过去,如在virtual sequence中使⽤,需要传递给virtual sequencer:
function void base_test::connect_phase(uvm_phase phase);
v_sqr.p_rm = ;
endfunction
UVM还提供其他函数,使得可以在不使⽤指针传递的情况下得到寄存器模型的指针:
山坡羊潼关怀古赏析
function void uvm_reg_block::get_root_blocks(ref uvm_reg_block blks[$]);
get_root_blocks函数得到验证平台上所有的根块(root block——最顶层的reg_block)。其使⽤⽰例如下:

本文发布于:2024-09-21 19:29:32,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/435561.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:寄存器   模型   操作   参数   类型   计数器   位宽
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议